﻿namespace WLFramework.Reflection
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using WLFramework.Common;

    public static class TypeHelper
    {
        private static readonly SafeDictionary<string, Type> _types =
            new SafeDictionary<string, Type>();


        public static bool IsNullable(this Type type)
        {
            Shield.AssertNotNull(ref type, "type");
            return type.IsGenericType && type.GetGenericTypeDefinition() == Types.Nullable;
        }

        public static bool IsEnumType(this Type type)
        {
            Shield.AssertNotNull(ref type, "type");
            return GetEnumType(type) != null;
        }

        public static bool IsPrimitiveType(this Type type)
        {
            return type.IsPrimitive //
                || Types.String == type
                || Types.Decimal == type
                || Types.Guid == type
                || Types.DateTime == type
                || Types.DBNull == type
                || TypeHelper.IsEnumType(type)
                || (type.IsNullable() && IsPrimitiveType(Nullable.GetUnderlyingType(type)));
        }

        /// <summary>
        /// 得到枚举类型
        /// </summary>
        /// <param name="enumType">枚举类型或Nullable枚举类型</param>
        /// <returns>返回枚举类型</returns>
        public static Type GetEnumType(this Type enumType)
        {
            Shield.AssertNotNull(ref enumType, "enumType");
            if (enumType.IsNullable())
                enumType = enumType.GetGenericArguments()[0];
            if (enumType.IsEnum)
                return enumType;
            return null;
        }

        public static string GetTypeAssemblyName(this Type type)
        {
            return type.AssemblyQualifiedName;
        }

        public static Type GetTypeFromCache(string name)
        {
            Type type;
            if (_types.TryGetValue(name, out type))
            {
                return type;
            }

            type = Type.GetType(name);
            _types.Add(name, type);
            return type;
        }

        public static bool IsOfType(this Type ObjectType, Type Type)
        {
            if (ObjectType == null)
                return false;
            if (Type == null)
                throw new ArgumentNullException("Type");
            if (Type == ObjectType || ObjectType.GetInterfaces().Any(x => x == Type))
                return true;
            if (ObjectType.BaseType == null)
                return false;
            return ObjectType.BaseType.IsOfType(Type);
        }
    }
}
